package com.sifang.POI.dianping;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.Session;
import org.htmlcleaner.TagNode;
import org.htmlcleaner.XPatherException;

public class AddDetailCommand extends MultiThreadsCommand {
	
	private int shopProcessed;
	
	public AddDetailCommand() {
		this(DEFAULT_MAX_THREADS);
	}
	
	public AddDetailCommand(int maxThreads) {
		super(maxThreads);
	}

	private void updateShop(Shop shop) throws IOException, XPatherException {
		StringBuilder sb = new StringBuilder(WebUtil.DIANPING_ROOT);
		sb.append("/shop/").append(shop.getShopId());
		String url = sb.toString();
		
		TagNode html = null;
		double lat = 0;
		double lng = 0;
		
		shop.setAvailable(ShopStatus.AVAILABLE);
		try {
			html = WebUtil.cleanUrl(url);
		} catch (FileNotFoundException e) {
			System.out.println(String.format("\nshop %d is unavailable", shop.getShopId()));
			shop.setAvailable(ShopStatus.UNAVAILABLE);
		}

		if (shop.getAvailable() == ShopStatus.AVAILABLE) {
			Object[] results = html.evaluateXPath("/body/script");
			
			for(Object result : results) {
				String text = ((TagNode) result).getText().toString();
				Pattern p = Pattern.compile("poi: '(.+?)'");
				Matcher m = p.matcher(text);
				if (m.find()) {
					String value = m.group(1);
					try {
						Location loc = decode(value);
						lat = loc.getLatitude();
						lng = loc.getLongitude();
					} catch (Exception e) {
						System.out.println(String.format("\n%d: bad location data", shop.getShopId()));
					}
					break;
				}
			}
		}
		
		String locString = String.format("%f,%f", lat, lng);
		shop.setLocation(locString);
		
		Session s = DpDb.getInstance().openSession();
		s.beginTransaction();
		s.update(shop);
		s.getTransaction().commit();
		s.close();
		
		String status = String.format("%d | %s", incShopProcessed(), getElapseTimeString());
		status = String.format("\r%-10d%40s", shop.getShopId(), status);
		System.out.print(status);
	}
	
	private Location decode(String source) {
		int i = -1;
		int h = 0;
		StringBuilder sb = new StringBuilder();
		int j = source.length() - 1;
		int g = source.charAt(j);
		source = source.substring(0, j);
		for(int e = 0; e < j; e++) {
			int d = Integer.parseInt(String.valueOf(source.charAt(e)), 36) - 10;
			if(d >= 10) {
				d = d - 7;
			}
			sb.append(Integer.toString(d, 36));
			if(d > h) {
				i = e;
				h = d;
			}
		}
		int a = Integer.parseInt(sb.substring(0, i), 16);
		int f = Integer.parseInt(sb.substring(i + 1), 16);
		double lng = (a + f - g) / 2;
		double lat = (f - lng) / 100000f;
		lng /= 100000;
		return new Location(lat, lng);
	}

	public synchronized int incShopProcessed() {
		shopProcessed += 1;
		return this.shopProcessed;
	}

	public static void main(String[] args) throws Exception {
		new AddDetailCommand(3).execute();
	}

	@Override
	protected List<? extends Runnable> getNextBatchWorks() {
		Session s = DpDb.getInstance().openSession();
		String query = "from Shop shop where shop.location is null";
		@SuppressWarnings("unchecked")
		List<Shop> shops = s.createQuery(query).setMaxResults(DpCmd.getInstance().getDbReadBatchSize()).list();
		s.close();
		List<Workitem> works = new ArrayList<Workitem>();
		for (Shop shop : shops) {
			works.add(new Workitem(shop));
		}
		return works;
	}
	
	class Workitem implements Runnable {
		private Shop shop;

		public Workitem(Shop shop) {
			this.shop = shop;
		}

		@Override
		public void run() {
			try {
				updateShop(shop);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
